#ifndef __M_CONNECT_H__
#define __M_CONNECT_H__

#include "muduo/proto/dispatcher.h"
#include "muduo/proto/codec.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpClient.h"
#include "muduo/net/EventLoopThread.h"
#include "muduo/base/CountDownLatch.h"

#include "channel.hpp"
#include "worker.hpp"

namespace mmq
{
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;
    public:
        Connection(const std::string &sip, int sport, const AsyncWorker::ptr &worker) 
            : _latch(1), _worker(worker),
            _client(_worker->_loopthread.startLoop(), muduo::net::InetAddress(sip, sport), "Client"),
            _dispatcher(std::bind(&Connection::OnUnkonwnMessage, this, 
                std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)),
            _codec(std::make_shared<ProtobufCodec>(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, 
                std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))),
            _channel_manager(std::make_shared<ChannelManager>())
        {
            _dispatcher.registerMessageCallback<BasicCommonResponse>(std::bind(&Connection::OnBasicResponse, this, 
                std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            _dispatcher.registerMessageCallback<BasicConsumeResponse>(std::bind(&Connection::OnConsumeResponse, this, 
                std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

            _client.setConnectionCallback(std::bind(&Connection::OnConnection, this, std::placeholders::_1));
            _client.setMessageCallback(std::bind(&ProtobufCodec::onMessage, _codec.get(), 
                std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

            _client.connect();
            _latch.wait(); // 阻塞等待，直到连接建立成功
        }

        // void Connect()
        // {
        //     _client.connect();
        //     _latch.wait(); // 阻塞等待，直到连接建立成功
        // }

        Channel::ptr OpenChannel()
        {
            Channel::ptr channel = _channel_manager->Create(_conn, _codec);
            bool ret = channel->OpenChannel();
            if(ret == false)
            {
                DLOG("打开信道失败！");
                return Channel::ptr();
            }
            return channel;
        }
        void CloseChannel(const Channel::ptr &channel)
        {
            channel->CloseChannel();
            _channel_manager->Remove(channel->Cid());
        }
    private:
        void OnBasicResponse(const muduo::net::TcpConnectionPtr &conn, const BasicCommonResponsePtr &message, muduo::Timestamp)
        {
            // 找到信道
            Channel::ptr channel = _channel_manager->Get(message->cid());
            if(channel.get() == nullptr)
            {
                DLOG("未找到信道信息！");
                return;
            }
            // 将得到的响应对象，添加到信道的基础相应hash_map中
            channel->PutBasicResponse(message);
        }
        void OnConsumeResponse(const muduo::net::TcpConnectionPtr &_conn, const BasicConsumeResponsePtr &message, muduo::Timestamp)
        {
            // 找到信道
            Channel::ptr channel = _channel_manager->Get(message->cid());
            if(channel.get() == nullptr)
            {
                DLOG("未找到信道信息！");
                return;
            }
            // 封装异步任务(消息处理任务)，抛入线程池
            _worker->_pool.Push([channel, message](){
                channel->Consume(message);
            });
        }

        void OnUnkonwnMessage(const muduo::net::TcpConnectionPtr &conn, const MessagePtr &message, muduo::Timestamp)
        {
            std::cout << "OnUnkonwnMessage: " << message->GetTypeName() << std::endl;
            _conn->shutdown();
        }
        void OnConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            if(conn->connected())
            {
                _conn = conn;
                _latch.countDown(); // 唤醒主线程的阻塞
            }
            else _conn.reset(); // 连接关闭时操作
        }


    private:
        muduo::CountDownLatch _latch; // 用于实现同步
        AsyncWorker::ptr _worker;
        muduo::net::TcpConnectionPtr _conn;
        muduo::net::TcpClient _client;
        ProtobufDispatcher _dispatcher;
        ProtobufCodecPtr _codec;
        
        ChannelManager::ptr _channel_manager;
    };
}
#endif